home *** CD-ROM | disk | FTP | other *** search
/ Plug Into a Brand New World / Plug Into a Brand New World Version 1.3.BIN / KW-585S25 / Linux / pl2303.c < prev    next >
C/C++ Source or Header  |  2002-02-13  |  21KB  |  631 lines

  1. /*
  2.  * Prolific USB Serial Adapter Driver
  3.  *
  4.  *  Copyright (C) 2001
  5.  *      Prolific Technology Inc.
  6.  *
  7.  *  This program is largely derived from work by the linux-usb group
  8.  *  and associated source files.  Please see the usb/serial files for
  9.  *  individual credits and copyrights.
  10.  *
  11.  */
  12. #include <linux/config.h>
  13. #include <linux/kernel.h>
  14. #include <linux/sched.h>
  15. #include <linux/signal.h>
  16. #include <linux/errno.h>
  17. #include <linux/poll.h>
  18. #include <linux/init.h>
  19. #include <linux/slab.h>
  20. #include <linux/fcntl.h>
  21. #include <linux/tty.h>
  22. #include <linux/tty_driver.h>
  23. #include <linux/tty_flip.h>
  24. #include <linux/module.h>
  25. #include <linux/spinlock.h>
  26. #include <linux/usb.h>
  27.  
  28. #ifdef USB_SERIAL_DEBUG
  29. static int  debug = 1;
  30. #else
  31. static int  debug;
  32. #endif
  33. #include "usb-serial.h"
  34. #include "pl2303.h"
  35.  
  36. #define TRUE  1
  37. #define FALSE 0
  38.  
  39. /* function prototypes for a Prolific USB Serial Adapter */
  40. static int                                prolific_sa_startup(struct usb_serial *serial);
  41. static void                               prolific_sa_shutdown(struct usb_serial *serial);
  42. static int                                prolific_sa_open(struct usb_serial_port *port, struct file *filp);
  43. static void                               prolific_sa_close(struct usb_serial_port *port, struct file *filp);
  44. static void                               prolific_sa_read_int_callback(struct urb *urb);
  45. static void                               prolific_sa_set_termios(struct usb_serial_port *port, struct termios *old);
  46. static int                                prolific_sa_ioctl(struct usb_serial_port  *port, struct file             *file,
  47.                                                             unsigned int            cmd, unsigned long           arg);
  48. static void                               prolific_sa_break_ctl(struct usb_serial_port *port, int break_state);
  49. static void                               prolific_set_dcr_state(struct usb_serial_port *port, int set);
  50. static int                              prolific_sa_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
  51. static void                              prolific_sa_write_bulk_callback(struct urb *urb);
  52.  
  53. static __devinitdata struct usb_device_id id_table_combined[] = {
  54.   { USB_DEVICE(PROLIFIC_SA_VID, PROLIFIC_SA_PID) },
  55.   { } /* Terminating entry */
  56. };
  57.  
  58. static __devinitdata struct usb_device_id prolific_sa_table[] = {
  59.   { USB_DEVICE(PROLIFIC_SA_VID, PROLIFIC_SA_PID) },
  60.   { } /* Terminating entry */
  61. };
  62.  
  63. MODULE_DEVICE_TABLE(usb, id_table_combined);
  64.  
  65. /* All of the device info needed for the Prolific serial converter */
  66. struct usb_serial_device_type prolific_sa_device =
  67. {
  68. name:
  69.   "Prolific USB Serial Adapter",
  70.   id_table : prolific_sa_table,                       /* the Prolific device */
  71.   needs_interrupt_in : MUST_HAVE,                     /* this device must have an interrupt in endpoint */
  72.   needs_bulk_in : MUST_HAVE,                          /* this device must have a bulk in endpoint */
  73.   needs_bulk_out : MUST_HAVE,                         /* this device must have a bulk out endpoint */
  74.   num_interrupt_in : 1,
  75.   num_bulk_in : 1,
  76.   num_bulk_out : 1,
  77.   num_ports : 1,
  78.   open : prolific_sa_open,
  79.   close : prolific_sa_close,
  80.   write : prolific_sa_write,
  81.   read_int_callback : prolific_sa_read_int_callback,  /* How we get the status info */
  82.   write_bulk_callback : prolific_sa_write_bulk_callback,
  83.   ioctl : prolific_sa_ioctl,
  84.   set_termios : prolific_sa_set_termios,
  85.   break_ctl : prolific_sa_break_ctl,
  86.   startup : prolific_sa_startup,
  87.   shutdown : prolific_sa_shutdown,
  88. };
  89.  
  90. struct line_coding {
  91.   unsigned long dwDTERate;
  92.   unsigned char bCharFormat;
  93.   unsigned char bParityType;
  94.   unsigned char bDatabits;
  95. };
  96.  
  97. struct prolific_sa_private {
  98.   unsigned long       control_state;
  99.   unsigned char       last_lsr;
  100.   unsigned char       last_msr;
  101.   int                 bad_flow_control;
  102.   struct line_coding  lineCoding;
  103.   unsigned short      RTSDTRState;
  104. };
  105.  
  106. /*
  107.  * ***************************************************************************
  108.  * Prolific USB Serial Adapter specific driver functions
  109.  * ***************************************************************************
  110.  */
  111. #define WDR_TIMEOUT (HZ * 5)  /* default urb timeout */
  112.  
  113. /* assumes that struct usb_serial *serial is available */
  114. #define BSA_USB_CMD(r, v) \
  115.   usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_CLASS_TYPE, (v), 0, NULL, 0, \
  116.                   WDR_TIMEOUT)
  117. #define BSA_USB_CMD_SET_DATA(r, v, data) \
  118.   usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_CLASS_TYPE, (v), 0, data, \
  119.                   sizeof(data), WDR_TIMEOUT)
  120. #define BSA_USB_CMD_SET_DATA_LEN(r, v, data, size) \
  121.   usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_CLASS_TYPE, (v), 0, data, \
  122.                   size, WDR_TIMEOUT)
  123. #define BSA_USB_CMD_SET_VENDOR(r, v, idx) \
  124.   usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_VENDOR_TYPE, (v), (idx), \
  125.                   NULL, 0, WDR_TIMEOUT)
  126. #define BSA_USB_CMD_GET_VENDOR_DATA(r, v, data, size) \
  127.   usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_GET_REQUEST_VENDOR_TYPE, (v), 0, data, \
  128.                   size, WDR_TIMEOUT)
  129.  
  130. /* do some startup allocations not currently performed by usb_serial_probe() */
  131. static int prolific_sa_startup(struct usb_serial *serial)
  132. {
  133.   struct usb_device           *dev = serial->dev;
  134.   struct prolific_sa_private  *priv;
  135.  
  136.   /* allocate the private data structure */
  137.   serial->port->private = kmalloc(sizeof(struct prolific_sa_private), GFP_KERNEL);
  138.   if(!serial->port->private)
  139.     return(-1); /* error */
  140.   priv = (struct prolific_sa_private *)serial->port->private;
  141.  
  142.   /* set initial values for control structures */
  143.   priv->control_state = 0;
  144.   priv->last_lsr = 0;
  145.   priv->last_msr = 0;
  146.  
  147.   /* see comments at top of file */
  148.   priv->bad_flow_control = (dev->descriptor.bcdDevice <= 0x0206) ? 1 : 0;
  149.   info("bcdDevice: %04x, bfc: %d", dev->descriptor.bcdDevice, priv->bad_flow_control);
  150.  
  151.   init_waitqueue_head(&serial->port->write_wait);
  152.  
  153.   return(0);
  154. }
  155.  
  156. static void prolific_sa_shutdown(struct usb_serial *serial)
  157. {
  158.   int i;
  159.  
  160.   dbg(__FUNCTION__);
  161.  
  162.   /* stop reads and writes on all ports */
  163.   for(i = 0; i < serial->num_ports; ++i) {
  164.     while(serial->port[i].open_count > 0) {
  165.       prolific_sa_close(&serial->port[i], NULL);
  166.     }
  167.  
  168.     /* My special items, the standard routines free my urbs */
  169.     if(serial->port[i].private)
  170.       kfree(serial->port[i].private);
  171.   }
  172. }
  173.  
  174. static int prolific_sa_open(struct usb_serial_port *port, struct file *filp)
  175. {
  176.   unsigned long flags;
  177.  
  178.   dbg(__FUNCTION__ " port %d", port->number);
  179.  
  180.   spin_lock_irqsave(&port->port_lock, flags);
  181.  
  182.   ++port->open_count;
  183.   MOD_INC_USE_COUNT;
  184.  
  185.   if(!port->active) {
  186.     port->active = 1;
  187.  
  188.     /*Start reading from the device*/
  189.  
  190.     /* TODO: Look at possibility of submitting mulitple URBs to device to
  191.          *       enhance buffering.  Win trace shows 16 initial read URBs.
  192.          */
  193.     port->read_urb->dev = port->serial->dev;
  194.     if(usb_submit_urb(port->read_urb))
  195.       err("usb_submit_urb(read bulk) failed");
  196.  
  197.     port->interrupt_in_urb->dev = port->serial->dev;
  198.     if(usb_submit_urb(port->interrupt_in_urb))
  199.       err(" usb_submit_urb(read int) failed");
  200.   }
  201.  
  202.   spin_unlock_irqrestore(&port->port_lock, flags);
  203.  
  204.   return 0;
  205. } /* prolific_sa_open */
  206.  
  207. static void prolific_sa_close(struct usb_serial_port *port, struct file *filp)
  208. {
  209.   unsigned long flags;
  210.  
  211.   dbg(__FUNCTION__ " port %d", port->number);
  212.  
  213.   spin_lock_irqsave(&port->port_lock, flags);
  214.  
  215.   --port->open_count;
  216.   MOD_DEC_USE_COUNT;
  217.  
  218.   if(port->open_count <= 0) {
  219.     /* shutdown our bulk reads and writes */
  220.     usb_unlink_urb(port->write_urb);
  221.     usb_unlink_urb(port->read_urb);
  222.     usb_unlink_urb(port->interrupt_in_urb); /* wgg - do I need this? I think so. */
  223.     port->active = 0;
  224.   }
  225.  
  226.   spin_unlock_irqrestore(&port->port_lock, flags);
  227. } /* prolific_sa_close */
  228.  
  229. static void prolific_sa_read_int_callback(struct urb *urb)
  230. {
  231.   struct usb_serial_port      *port = (struct usb_serial_port *)urb->context;
  232.   struct prolific_sa_private  *priv = (struct prolific_sa_private *)port->private;
  233.   struct usb_serial           *serial;
  234.   unsigned char               *data = urb->transfer_buffer;
  235.  
  236.   /* the urb might have been killed. */
  237.   if(urb->status)
  238.     return;
  239.  
  240.   if(port_paranoia_check(port, "prolific_sa_read_interrupt"))
  241.     return;
  242.  
  243.   serial = port->serial;
  244.   if(serial_paranoia_check(serial, "prolific_sa_read_interrupt"))
  245.     return;
  246.  
  247.   usb_serial_debug_data(__FILE__, __FUNCTION__, urb->actual_length, data);
  248.  
  249.   /* Handle known interrupt data */
  250.  
  251.   /* ignore data[0] and data[1] */
  252.   priv->last_msr = data[PROLIFIC_SA_MSR_INDEX];
  253.   dbg("interrupt: 0x%02x", priv->last_msr);
  254.  
  255.   /* Record Control Line states */
  256.   if(priv->last_msr & PROLIFIC_SA_MSR_DSR)
  257.     priv->control_state |= TIOCM_DSR;
  258.   else
  259.     priv->control_state &= ~TIOCM_DSR;
  260.  
  261.   if(priv->last_msr & PROLIFIC_SA_MSR_CTS)
  262.     priv->control_state |= TIOCM_CTS;
  263.   else
  264.     priv->control_state &= ~TIOCM_CTS;
  265.  
  266.   if(priv->last_msr & PROLIFIC_SA_MSR_RI)
  267.     priv->control_state |= TIOCM_RI;
  268.   else
  269.     priv->control_state &= ~TIOCM_RI;
  270.  
  271.   if(priv->last_msr & PROLIFIC_SA_MSR_CD)
  272.     priv->control_state |= TIOCM_CD;
  273.   else
  274.     priv->control_state &= ~TIOCM_CD;
  275.  
  276.   /* Now to report any errors */
  277.   priv->last_lsr = data[PROLIFIC_SA_LSR_INDEX];
  278. #if 0
  279.   if(priv->last_lsr & PROLIFIC_SA_LSR_ERR) {
  280.     tty = port->tty;
  281.  
  282.     /* Overrun Error */
  283.     if(priv->last_lsr & PROLIFIC_SA_LSR_OE) {
  284.     }
  285.  
  286.     /* Parity Error */
  287.     if(priv->last_lsr & PROLIFIC_SA_LSR_PE) {
  288.     }
  289.  
  290.     /* Framing Error */
  291.     if(priv->last_lsr & PROLIFIC_SA_LSR_FE) {
  292.     }
  293.  
  294.     /* Break Indicator */
  295.     if(priv->last_lsr & PROLIFIC_SA_LSR_BI) {
  296.     }
  297.   }
  298. #endif
  299.   /* INT urbs are automatically re-submitted */
  300. }
  301.  
  302. static void prolific_sa_set_termios(struct usb_serial_port *port, struct termios *old_termios)
  303. {
  304.   struct usb_serial           *serial = port->serial;
  305.   struct prolific_sa_private  *priv = (struct prolific_sa_private *)port->private;
  306.   unsigned int                cflag = port->tty->termios->c_cflag;
  307.   unsigned int                old_cflag = old_termios->c_cflag;
  308.   unsigned long               rate = 115200;
  309.   unsigned char               format = 0, parity = 0, size = 8;
  310.  
  311.   info(__FUNCTION__ " - cflag: 0x%4X, old_cflag: 0x%4X", cflag, old_cflag);
  312.  
  313.   /* Set the baud rate */
  314.   if((cflag & CBAUD) != (old_cflag & CBAUD)) {
  315.     /* reassert DTR and (maybe) RTS on transition from B0 */
  316.     if((old_cflag & CBAUD) == B0) {
  317.       priv->control_state |= (TIOCM_DTR | TIOCM_RTS);
  318.       if(BSA_USB_CMD(PROLIFIC_SA_SET_CTRL_LINE_REQUEST, priv->RTSDTRState |= 0x0001) < 0)
  319.         err("Set DTR error");
  320.  
  321.       /* don't set RTS if using hardware flow control */
  322.       if(!(old_cflag & CRTSCTS))
  323.         if(BSA_USB_CMD(PROLIFIC_SA_SET_CTRL_LINE_REQUEST, priv->RTSDTRState |= 0x0002) < 0)
  324.           err("Set RTS error");
  325.     }
  326.  
  327.     switch(cflag & CBAUD)
  328.     {
  329.       case B150:    rate = 150; break;
  330.       case B300:    rate = 300; break;
  331.       case B600:    rate = 600; break;
  332.       case B1200:   rate = 1200; break;
  333.       case B2400:   rate = 2400; break;
  334.       case B4800:   rate = 4800; break;
  335.       case B9600:   rate = 9600; break;
  336.       case B19200:  rate = 19200; break;
  337.       case B38400:  rate = 38400; break;
  338.       case B115200: rate = 115200; break;
  339.       case B230400: rate = 230400; break;
  340.       case B460800: rate = 460800; break;
  341.     }
  342.  
  343.     if((cflag & CBAUD) == B0) {
  344.       /* Drop RTS and DTR */
  345.       priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
  346.       if(BSA_USB_CMD(PROLIFIC_SA_SET_CTRL_LINE_REQUEST, priv->RTSDTRState &= 0xFFFE) < 0)
  347.         err("DTR LOW error");
  348.       if(BSA_USB_CMD(PROLIFIC_SA_SET_CTRL_LINE_REQUEST, priv->RTSDTRState &= 0xFFFD) < 0)
  349.         err("RTS LOW error");
  350.     }
  351.   }
  352.  
  353.   /* set the parity */
  354.   if((cflag & (PARENB | PARODD)) != (old_cflag & (PARENB | PARODD))) {
  355.     if(cflag & PARENB)
  356.       parity = (cflag & PARODD) ? 0x01 : 0x02;
  357.     else
  358.       parity = 0;
  359.   }
  360.  
  361.   /* set the number of data bits */
  362.   if((cflag & CSIZE) != (old_cflag & CSIZE)) {
  363.     switch(cflag & CSIZE)
  364.     {
  365.       case CS5: size = 5; break;
  366.       case CS6: size = 6; break;
  367.       case CS7: size = 7; break;
  368.       case CS8: size = 8; break;
  369.     }
  370.   }
  371.  
  372.   /* set the number of stop bits */
  373.   if((cflag & CSTOPB) != (old_cflag & CSTOPB))
  374.     format = (cflag & CSTOPB) ? 0x02 : 0x00;
  375.  
  376.   /* Set flow control */
  377.   if((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
  378.     if(cflag & CRTSCTS)
  379.       prolific_set_dcr_state(port, TRUE);
  380.     else
  381.       prolific_set_dcr_state(port, FALSE);
  382.   }
  383.  
  384.   priv->lineCoding.dwDTERate = rate;
  385.   priv->lineCoding.bCharFormat = format;
  386.   priv->lineCoding.bParityType = parity;
  387.   priv->lineCoding.bDatabits = size;
  388.  
  389.   dbg(__FUNCTION__ "==> dwDTERate: %ld - bCharFormat: %d - bParityType: %d - bDatabits: %d", rate, format, parity, size);
  390.  
  391.   if(BSA_USB_CMD_SET_DATA_LEN(PROLIFIC_SA_SET_LINECODING_REQUEST, 0, &priv->lineCoding, 7) < 0)
  392.     err("Set_line_coding request error");
  393. } /* prolific_sa_set_termios */
  394.  
  395. static void prolific_sa_break_ctl(struct usb_serial_port *port, int break_state)
  396. {
  397.   struct usb_serial *serial = port->serial;
  398.  
  399.   if(break_state) {
  400.     if(BSA_USB_CMD(PROLIFIC_SA_SET_BREAK_REQUEST, 0xFFFF) < 0)
  401.       err("Set break_ctl %d fail", break_state);
  402.   }
  403.   else {
  404.     if(BSA_USB_CMD(PROLIFIC_SA_SET_BREAK_REQUEST, 0) < 0)
  405.       err("Set break_ctl %d fail", break_state);
  406.   }
  407. }
  408.  
  409. static int prolific_sa_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
  410. {
  411.   struct usb_serial           *serial = port->serial;
  412.   __u16                       urb_value;  /* Will hold the new flags */
  413.   struct prolific_sa_private  *priv = (struct prolific_sa_private *)port->private;
  414.   int                         ret, mask;
  415.  
  416.   info(__FUNCTION__ " cmd: %04x", cmd);
  417.  
  418.   /* Based on code from acm.c and others */
  419.   switch(cmd)
  420.   {
  421.     case TIOCMGET:
  422.       dbg("TIOCMGET: control_state - 0x%04x", (unsigned int)priv->control_state);
  423.       return put_user(priv->control_state, (unsigned long *)arg);
  424.       break;
  425.  
  426.     case TIOCMSET:  /* Turns on and off the lines as specified by the mask */
  427.     case TIOCMBIS:  /* turns on (Sets) the lines as specified by the mask */
  428.     case TIOCMBIC:  /* turns off (Clears) the lines as specified by the mask */
  429.       if((ret = get_user(mask, (unsigned long *)arg)))
  430.         return ret;
  431.  
  432.       dbg("cmd: 0x%04X mask: 0x%04X", cmd, mask);
  433.  
  434.       if((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
  435.         /* RTS needs set */
  436.         urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || (cmd == TIOCMBIS) ? 1 : 0;
  437.         if(urb_value)
  438.           priv->control_state |= TIOCM_RTS;
  439.         else
  440.           priv->control_state &= ~TIOCM_RTS;
  441.  
  442.         if(urb_value) {
  443.           if((ret = BSA_USB_CMD(PROLIFIC_SA_SET_CTRL_LINE_REQUEST, priv->RTSDTRState |= 0x0002)) < 0) {
  444.             err("Set RTS error %d", ret);
  445.             return(ret);
  446.           }
  447.         }
  448.         else {
  449.           if((ret = BSA_USB_CMD(PROLIFIC_SA_SET_CTRL_LINE_REQUEST, priv->RTSDTRState &= 0xFFFD)) < 0) {
  450.             err("Clear RTS error %d", ret);
  451.             return(ret);
  452.           }
  453.         }
  454.  
  455.         if((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
  456.           /* DTR needs set */
  457.           urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || (cmd == TIOCMBIS) ? 1 : 0;
  458.           if(urb_value)
  459.             priv->control_state |= TIOCM_DTR;
  460.           else
  461.             priv->control_state &= ~TIOCM_DTR;
  462.  
  463.           if(urb_value) {
  464.             if((ret = BSA_USB_CMD(PROLIFIC_SA_SET_CTRL_LINE_REQUEST, priv->RTSDTRState |= 0x0001)) < 0) {
  465.               err("Set DTR error %d", ret);
  466.               return(ret);
  467.             }
  468.           }
  469.           else {
  470.             if((ret = BSA_USB_CMD(PROLIFIC_SA_SET_CTRL_LINE_REQUEST, priv->RTSDTRState &= 0xFFFE)) < 0) {
  471.               err("Clear DTR error %d", ret);
  472.               return(ret);
  473.             }
  474.           }
  475.         }
  476.       }
  477.       break;
  478.  
  479.     case TIOCMIWAIT:
  480.       /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
  481.  
  482.       /* TODO */
  483.       return(0);
  484.  
  485.     case TIOCGICOUNT:
  486.       /* return count of modemline transitions */
  487.  
  488.       /* TODO */
  489.       return 0;
  490.  
  491.     default:
  492.       dbg("prolific_sa_ioctl arg not supported - 0x%04x", cmd);
  493.       return(-ENOIOCTLCMD);
  494.       break;
  495.   }
  496.  
  497.   return 0;
  498. } /* prolific_sa_ioctl */
  499.  
  500. static void prolific_set_dcr_state(struct usb_serial_port *port, int set)
  501. {
  502.   struct usb_serial           *serial = port->serial;
  503.   unsigned short              code = 0;
  504.   unsigned char               old_value = 0;
  505.   unsigned short              new_value;
  506.   int                         ret;
  507.  
  508.   struct prolific_sa_private  *priv = (struct prolific_sa_private *)port->private;
  509.  
  510.   info(__FUNCTION__ " - set: %d", set);
  511.  
  512.   if(BSA_USB_CMD_GET_VENDOR_DATA(PROLIFIC_SA_VENDOR_REQUEST, code, &old_value, sizeof(old_value)) < 0)
  513.     err("Get DCR request error");
  514.  
  515.   if(set)
  516.     new_value = old_value | 0x40;
  517.   else
  518.     new_value = old_value & 0x3F;
  519.  
  520.   if(BSA_USB_CMD_SET_VENDOR(PROLIFIC_SA_VENDOR_REQUEST, code, new_value) < 0)
  521.     err("Set DCR request error");
  522.  
  523.   if(set) {
  524.     if((ret = BSA_USB_CMD(PROLIFIC_SA_SET_CTRL_LINE_REQUEST, priv->RTSDTRState |= 0x0002)) < 0) {
  525.       err("Set RTS error %d", ret);
  526.       return;
  527.     }
  528.   }
  529. }
  530.  
  531. static int prolific_sa_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
  532. {
  533.   struct usb_serial *serial = port->serial;
  534.   unsigned long     flags;
  535.   int               result;
  536.  
  537.   dbg(__FUNCTION__ " - port %d", port->number);
  538.  
  539.   if(count == 0) {
  540.     dbg(__FUNCTION__ " - write request of 0 bytes");
  541.     return(0);
  542.   }
  543.  
  544.   /* only do something if we have a bulk out endpoint */
  545.   if(serial->num_bulk_out) {
  546. /*
  547.     if(port->write_urb->status == -EINPROGRESS) {
  548.       dbg(__FUNCTION__ " - already writing");
  549.       return(0);
  550.     }
  551. */
  552.     while(port->write_urb->status == -EINPROGRESS)
  553.       schedule();
  554.  
  555.     spin_lock_irqsave(&port->port_lock, flags);
  556.     count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
  557.  
  558.     usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf);
  559.  
  560.     if(from_user) {
  561.       copy_from_user(port->write_urb->transfer_buffer, buf, count);
  562.     }
  563.     else {
  564.       memcpy(port->write_urb->transfer_buffer, buf, count);
  565.     }
  566.  
  567.     /* set up our urb */
  568.     FILL_BULK_URB(port->write_urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
  569.                   port->write_urb->transfer_buffer, count,
  570.                   prolific_sa_write_bulk_callback,
  571.                   port);
  572.  
  573.     /* send the data out the bulk port */
  574.     result = usb_submit_urb(port->write_urb);
  575.     if(result) {
  576.       err(__FUNCTION__ " - failed submitting write urb, error %d", result);
  577.       spin_unlock_irqrestore(&port->port_lock, flags);
  578.       return 0;
  579.     }
  580.  
  581.     spin_unlock_irqrestore(&port->port_lock, flags);
  582.     return(count);
  583.   }
  584.  
  585.   /* no bulk out, so return 0 bytes written */
  586.   return(0);
  587. }
  588.  
  589. static void prolific_sa_write_bulk_callback(struct urb *urb)
  590. {
  591.   struct usb_serial_port  *port = (struct usb_serial_port *)urb->context;
  592.   struct usb_serial       *serial = get_usb_serial(port, __FUNCTION__);
  593.  
  594.   dbg(__FUNCTION__ " - port %d", port->number);
  595.  
  596.   if(!serial) {
  597.     dbg(__FUNCTION__ " - bad serial pointer, exiting");
  598.     return;
  599.   }
  600.  
  601.   if(urb->status) {
  602.     dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
  603.     return;
  604.   }
  605.  
  606.   queue_task(&port->tqueue, &tq_immediate);
  607.   mark_bh(IMMEDIATE_BH);
  608.  
  609.   return;
  610. }
  611.  
  612. static int __init prolific_sa_init(void)
  613. {
  614.   usb_serial_register(&prolific_sa_device);
  615.   return 0;
  616. }
  617.  
  618. static void __exit prolific_sa_exit(void)
  619. {
  620.   usb_serial_deregister(&prolific_sa_device);
  621. }
  622.  
  623. module_init(prolific_sa_init);
  624. module_exit(prolific_sa_exit);
  625.  
  626. MODULE_AUTHOR("Sam Kuo");
  627. MODULE_DESCRIPTION("Prolific USB-Serial converter driver");
  628.  
  629. MODULE_PARM(debug, "i");
  630. MODULE_PARM_DESC(debug, "Debug enabled or not");
  631.